Handle resolution changes in the GDK backend code
authorOwen W. Taylor <otaylor@fishsoup.net>
Fri, 11 Jul 2014 20:42:38 +0000 (16:42 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 13 Jul 2014 19:35:23 +0000 (15:35 -0400)
gdk_x11_display_set_window_scale() affects the interpretation of the
Xft/DPI XSETTING - it is substituted inside GDK with the value of
Gdk/UnscaledDPI xsetting. However, this change is not propagated to
GTK+ and from GTK+ back to gdk_screen_set_resolution() until the
main loop is run.

Fix this by handling the screen resolution directly in gdk/x11.
This requires duplication of code between GDK and GTK+ since we still
have to handle DPI in GTK+ in the case that GdkSettings:gtk-xft-dpi
is set by the application.

https://bugzilla.gnome.org/show_bug.cgi?id=733076

gdk/gdkinternals.h
gdk/gdkscreen.c
gdk/gdkscreenprivate.h
gdk/quartz/gdkscreen-quartz.c
gdk/wayland/gdkscreen-wayland.c
gdk/x11/xsettings-client.c
gtk/gtksettings.c

index a2c4e53a51789b27f859f3ec468b9e2ed297e77f..f58ccb00845d3aa73d50bf378c9fb1b16cbfc8f2 100644 (file)
@@ -345,6 +345,8 @@ gboolean   _gdk_window_update_viewable   (GdkWindow      *window);
 void       _gdk_window_process_updates_recurse (GdkWindow *window,
                                                 cairo_region_t *expose_region);
 
+void       _gdk_screen_set_resolution    (GdkScreen      *screen,
+                                          gdouble         dpi);
 void       _gdk_screen_close             (GdkScreen      *screen);
 
 /*****************************************
index e2cbfb7d0d955401f5be91451f56813bf6f18a64..cc170c5b4bc22d6d7b2aafe9c420fe4e7e991351 100644 (file)
@@ -459,6 +459,31 @@ gdk_screen_set_resolution (GdkScreen *screen,
 {
   g_return_if_fail (GDK_IS_SCREEN (screen));
 
+  if (dpi < 0)
+    dpi = -1.0;
+
+  screen->resolution_set = TRUE;
+
+  if (screen->resolution != dpi)
+    {
+      screen->resolution = dpi;
+
+      g_object_notify (G_OBJECT (screen), "resolution");
+    }
+}
+
+/* Just like gdk_screen_set_resolution(), but doesn't change
+ * screen->resolution. This is us to allow us to distinguish
+ * resolution changes that the backend picks up from resolution
+ * changes made through the public API - perhaps using
+ * g_object_set(<GtkSetting>, "gtk-xft-dpi", ...);
+ */
+void
+_gdk_screen_set_resolution (GdkScreen *screen,
+                            gdouble    dpi)
+{
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+
   if (dpi < 0)
     dpi = -1.0;
 
index 23cf1bdae25fe2a77b90263d7b5c819cb5db59b3..15c405604c7814daf6e02b6c4f0e5aac69d2f7bb 100644 (file)
@@ -35,6 +35,7 @@ struct _GdkScreen
 
   cairo_font_options_t *font_options;
   gdouble resolution; /* pixels/points scale factor for fonts */
+  guint resolution_set : 1; /* resolution set through public API */
   guint closed : 1;
 };
 
index e4d409023fe793e252717a8ae744ec112ea6eda1..ca655a5a6ab9db3f2f8634e615d02095b0a80cb9 100644 (file)
@@ -75,8 +75,8 @@ gdk_quartz_screen_init (GdkQuartzScreen *quartz_screen)
   NSScreen *nsscreen;
 
   nsscreen = [[NSScreen screens] objectAtIndex:0];
-  gdk_screen_set_resolution (screen,
-                             72.0 * [nsscreen userSpaceScaleFactor]);
+  _gdk_screen_set_resolution (screen,
+                              72.0 * [nsscreen userSpaceScaleFactor]);
 
   gdk_quartz_screen_calculate_layout (quartz_screen);
 
index 4cbc51e493ef61300df2bc15ee35af73fffe0d77..baa1bc888c7db171f1be0ce651077557d14044fe 100644 (file)
@@ -477,7 +477,22 @@ update_xft_settings (GdkScreen *screen)
 
   if (screen_wayland->xft_settings.dpi != xft_settings.dpi)
     {
+      double dpi = xft_settings.dpi / 1024.;
+      const char *scale_env;
+      double scale;
+
       screen_wayland->xft_settings.dpi = xft_settings.dpi;
+
+      scale_env = g_getenv ("GDK_DPI_SCALE");
+      if (scale_env)
+        {
+          scale = g_ascii_strtod (scale_env, NULL);
+          if (scale != 0 && dpi > 0)
+            dpi *= scale;
+        }
+
+      _gdk_screen_set_resolution (screen, dpi);
+
       notify_setting (screen, "gtk-xft-dpi");
     }
 }
index 87b4addbea4adef2ec1c120866cfdc14093f22c7..f807e52880f02a41c4b38ef4e10f392bf5e99096 100644 (file)
@@ -402,6 +402,8 @@ static void
 read_settings (GdkX11Screen *x11_screen,
                gboolean      do_notify)
 {
+  GdkScreen *screen = GDK_SCREEN (x11_screen);
+
   Atom type;
   int format;
   unsigned long n_items;
@@ -466,6 +468,41 @@ read_settings (GdkX11Screen *x11_screen,
     g_hash_table_unref (old_list);
 
   g_value_init (&value, G_TYPE_INT);
+
+  if (!screen->resolution_set)
+    {
+      /* This code is duplicated with gtksettings.c:settings_update_resolution().
+       * The update of the screen resolution needs to happen immediately when
+       * gdk_x11_display_set_window_scale() is called, and not wait for events
+       * to be processed, so we can't always handling it in gtksettings.c.
+       * But we can't always handle it here because the DPI can be set through
+       * GtkSettings, which we don't have access to.
+       */
+      int dpi_int = 0;
+      double dpi;
+      const char *scale_env;
+      double scale;
+
+      if (gdk_screen_get_setting (GDK_SCREEN (x11_screen),
+                                  "gtk-xft-dpi", &value))
+        dpi_int = g_value_get_int (&value);
+
+      if (dpi_int > 0)
+        dpi = dpi_int / 1024.;
+      else
+        dpi = -1.;
+
+      scale_env = g_getenv ("GDK_DPI_SCALE");
+      if (scale_env)
+        {
+          scale = g_ascii_strtod (scale_env, NULL);
+          if (scale != 0 && dpi > 0)
+            dpi *= scale;
+        }
+
+      _gdk_screen_set_resolution (screen, dpi);
+    }
+
   if (!x11_screen->fixed_window_scale &&
       gdk_screen_get_setting (GDK_SCREEN (x11_screen),
                              "gdk-window-scaling-factor", &value))
index 64912ceeaf8c6d81dc263642602de729f2e45047..7549c8d9ab122396fda8d592143698f75f873d76 100644 (file)
@@ -2944,24 +2944,31 @@ settings_update_resolution (GtkSettings *settings)
   const char *scale_env;
   double scale;
 
-  g_object_get (settings,
-                "gtk-xft-dpi", &dpi_int,
-                NULL);
+  /* We handle this here in the case that the dpi was set on the GtkSettings
+   * object by the application. Other cases are handled in
+   * xsettings-client.c:read-settings(). See comment there for the rationale.
+   */
+  if (priv->property_values[PROP_XFT_DPI - 1].source == GTK_SETTINGS_SOURCE_APPLICATION)
+    {
+      g_object_get (settings,
+                    "gtk-xft-dpi", &dpi_int,
+                    NULL);
 
-  if (dpi_int > 0)
-    dpi = dpi_int / 1024.;
-  else
-    dpi = -1.;
+      if (dpi_int > 0)
+        dpi = dpi_int / 1024.;
+      else
+        dpi = -1.;
 
-  scale_env = g_getenv ("GDK_DPI_SCALE");
-  if (scale_env)
-    {
-      scale = g_ascii_strtod (scale_env, NULL);
-      if (scale != 0 && dpi > 0)
-       dpi *= scale;
-    }
+      scale_env = g_getenv ("GDK_DPI_SCALE");
+      if (scale_env)
+        {
+          scale = g_ascii_strtod (scale_env, NULL);
+          if (scale != 0 && dpi > 0)
+            dpi *= scale;
+        }
 
-  gdk_screen_set_resolution (priv->screen, dpi);
+      gdk_screen_set_resolution (priv->screen, dpi);
+    }
 }
 
 static void